;---------------------------------------------------------------- ;内容 ; サブルーチンの所要時間を測るためのルーチンです。 ; スーパーバイザモードで呼び出して下さい。 ; Timer-CとTimer-Dを使用するので,Timer-Dが使用中の場合は停止しておいて下さい。 ; ;呼び出し手順 ; move.l #param,-(sp) ;初期化ルーチンのパラメータ(ループ回数など) ; pea.l tini ;後始末ルーチン(不要ならば0) ; pea.l init ;初期化ルーチン(不要ならば0) ; pea.l main ;計測するルーチン ; jsr optime ;d0.l=計測するルーチンの所要時間(μs単位で12799まで) ; lea.l (16,sp),sp ; ;リンク時の注意事項 ; lk -e16のように16バイトアラインメントでリンクして下さい。 ; ;各ルーチンの設定 ; 各ルーチンはスーパーバイザモードで呼ばれます。 ; sspは復帰アドレスをプッシュする前に16バイト単位にアラインメントされています。 ; 初期化ルーチンから後始末ルーチンまでd0-d7/a0-a5を自由に使って構いません。 ; a6レジスタはサブルーチンのアドレスとして使用していますが,破壊しても構いません。 ; 初期化ルーチンでレジスタに設定した値はa6を除いてそのまま計測するルーチンに渡されます。 ; 例えば,初期化ルーチンでカウンタを初期化し,計測ルーチンでループを開始できます。 ; ;各ルーチンの呼び出し順序 ; 初期化ルーチン→計測するルーチン→後始末ルーチンの順序で,2回呼び出します。 ; 1回目は各ルーチンを命令キャッシュに乗せるための準備です。 ; 2回目の,計測するルーチンの所要時間をμs単位で計測します。 ; なお,所要時間には呼び出しと復帰の時間が含まれています。 ; 一連の呼び出しの間,割り込みは止められています。 ; ;計測結果 ; 計測結果はd0.lにμs単位で格納されます。 ; 最大計測時間は12799μsです。これを超えると正確に計測できません。 ; 50MHzのとき1clock=0.02μsですから,適当な回数だけループさせるなどして下さい。 ;---------------------------------------------------------------- .cpu 68000 ;---------------------------------------------------------------- ;MFPのアドレス GPIPDR equ $00E88001 AER equ $00E88003 DDR equ $00E88005 IERA equ $00E88007 IERB equ $00E88009 IPRA equ $00E8800B IPRB equ $00E8800D ISRA equ $00E8800F ISRB equ $00E88011 IMRA equ $00E88013 IMRB equ $00E88015 VECTR equ $00E88017 TACR equ $00E88019 TBCR equ $00E8801B TCDCR equ $00E8801D TADR equ $00E8801F TBDR equ $00E88021 TCDR equ $00E88023 TDDR equ $00E88025 SCR equ $00E88027 UCR equ $00E88029 RSR equ $00E8802B TSR equ $00E8802D UDR equ $00E8802F ;---------------------------------------------------------------- ;ベクタアドレス TIMER_D_VECTOR equ $0110 ;---------------------------------------------------------------- ;間接サブルーチンコール(000用) jsrr .macro dst .local next move.l dst,-(sp) ;dspがspを参照している場合があるので最初にプッシュする move.l (sp),-(sp) move.l #next,(4,sp) rts next: .endm ;---------------------------------------------------------------- ;パラメータの内容 .offset 0 p_pc .ds.l 1 ;復帰アドレス p_main: .ds.l 1 ;計測するルーチン p_init: .ds.l 1 ;初期化ルーチン p_tini: .ds.l 1 ;後始末ルーチン p_param: .ds.l 1 ;初期化ルーチンのパラメータ(ループ回数など) .text ;---------------------------------------------------------------- ;スタックの内容 .offset 0 v_main: .ds.l 1 ;計測するルーチン v_init: .ds.l 1 ;初期化ルーチン v_tini: .ds.l 1 ;後始末ルーチン v_param: .ds.l 1 ;初期化ルーチンのパラメータ(ループ回数など) v_ssp: .ds.l 1 ;元のスタックポインタ(この位置+16以上) v_test: .ds.b 1 ;0=本番,-1=リハーサル v_tcdcr: .ds.b 1 ;TCDCRのワーク v_imrb: .ds.b 1 ;IMRBのワーク v_ierb: .ds.b 1 ;IERBのワーク .align 16 v_size: .text ;---------------------------------------------------------------- ;計測ルーチン ; スーパーバイザモードで呼び出すこと ;<(4,sp).l:計測するルーチン ;<(8,sp).l:初期化ルーチン(不要ならば0) ;<(12,sp).l:後始末ルーチン(不要ならば0) ;>d0.l:所要時間(単位はμs,0〜12799),-1=Timer-Dが使用中 ;---------------------------------------------------------------- .even _optime:: movem.l d1-d7/a0-a6,-(sp) ;ここではa6も必要 lea.l (4*14,sp),a6 ;pcのアドレス ;Timer-Dの使用状態の確認 btst.b #4,IERB beq @f ;Timer-Dは使用されていない movea.l $1C20.w,a0 ;Humanの先頭 move.l (8,a0),d0 ;Humanの末尾 cmp.l TIMER_D_VECTOR,d0 bcc @f ;Timer-DはHumanが使用中 moveq.l #-1,d0 ;Timer-DはHuman以外が使用中 bra 99f @@: ;割り込み禁止 move.w sr,-(sp) ori.w #$0700,sr ;ワークの確保とアラインメント move.l sp,d0 and.l #$0000000F,d0 neg.l d0 move.l sp,(-v_size+v_ssp,sp,d0.l) ;割り込みを止めてあるので, lea.l (-v_size,sp,d0.l),sp ;この間に割り込みなどでスタックが壊れることはない ;各ルーチンのアドレスをセット move.l (p_main,a6),(v_main,sp) ;計測するルーチン lea.l (dummy_routine,pc),a0 move.l (p_init,a6),d0 beq @f movea.l d0,a0 @@: move.l a0,(v_init,sp) ;初期化ルーチン lea.l (dummy_routine,pc),a0 move.l (p_tini,a6),d0 beq @f movea.l d0,a0 @@: move.l a0,(v_tini,sp) ;後始末ルーチン move.l (p_param,a6),(v_param,sp) ;初期化ルーチンのパラメータ ;タイマ設定 move.b IERB,(v_ierb,sp) move.b IMRB,(v_imrb,sp) move.b TCDCR,(v_tcdcr,sp) andi.b #%11001111,IERB ;Timer-C/D割り込み停止 andi.b #%11001111,IMRB ;Timer-C/D割り込み禁止 sf.b TCDCR ;Timer-C/Dカウント停止 @@: tst.b TCDCR ;完全に停止するまで待つ bne @b ;000〜010と020〜060で処理を分ける @@: moveq.l #1,d0 .cpu 68020 and.b (@b-1,pc,d0.l*2),d0 .cpu 68000 bne measure_020 ;000〜010用の計測ルーチン measure_000: st.b (v_test,sp) ;リハーサル retry_000: movea.l (v_init,sp),a6 move.l (v_param,sp),-(sp) jsr (a6) ;初期化ルーチンを呼ぶ addq.l #4,sp sf.b TCDR ;Timer-Cカウンタクリア @@: tst.b TCDR ;カウンタが更新されるまで待つ bne @b sf.b TDDR ;Timer-Dカウンタクリア @@: tst.b TDDR ;カウンタが更新されるまで待つ bne @b movea.l (v_main,sp),a6 ;計測するルーチン ;カウント開始 ; TCCR TDCR move.b #%0111_0001,TCDCR ;Timer-C/Dカウント開始 ; Timer-Cは1/200プリスケール(50μs) ; Timer-Dは1/4プリスケール(1μs) ;計測するルーチンを呼び出す jsr (a6) ;カウント停止 sf.b TCDCR ;Timer-C/Dカウント停止 @@: tst.b TCDCR ;完全に停止するまで待つ bne @b movea.l (v_tini,sp),a6 jsr (a6) ;後始末ルーチンを呼ぶ not.b (v_test,sp) beq retry_000 bra measure_done ;020〜060用の計測ルーチン .cpu 68020 measure_020: st.b (v_test,sp) ;リハーサル retry_020: movea.l (v_init,sp),a6 move.l (v_param,sp),-(sp) jsr (a6) ;初期化ルーチンを呼ぶ addq.l #4,sp sf.b TCDR ;Timer-Cカウンタクリア @@: tst.b TCDR ;カウンタが更新されるまで待つ bne @b sf.b TDDR ;Timer-Dカウンタクリア @@: tst.b TDDR ;カウンタが更新されるまで待つ bne @b movea.l (v_main,sp),a6 ;計測するルーチン bra @f .align 16 .ds.w 16-3 @@: ;カウント開始 ; TCCR TDCR move.b #%0111_0001,TCDCR ;Timer-C/Dカウント開始 ; Timer-Cは1/200プリスケール(50μs) ; Timer-Dは1/4プリスケール(1μs) ;計測するルーチンを呼び出す jsr (a6) ;カウント停止 sf.b TCDCR ;Timer-C/Dカウント停止 @@: tst.b TCDCR ;完全に停止するまで待つ bne @b movea.l (v_tini,sp),a6 jsr (a6) ;後始末ルーチンを呼ぶ not.b (v_test,sp) beq retry_020 .cpu 68000 ;計測終わり measure_done: ;タイマ取得 moveq.l #0,d0 moveq.l #0,d1 sub.b TCDR,d0 ;Timer-Cカウント数 sub.b TDDR,d1 ;Timer-Dカウント数(オーバーフローあり) ;タイマ後始末 move.b #200,TCDR ;Timer-Cカウンタ復元 move.b #20,TDDR ;Timer-Dカウンタ復元 move.b (v_imrb,sp),IMRB move.b (v_ierb,sp),IERB move.b (v_tcdcr,sp),TCDCR ;ワークの開放 movea.l (v_ssp,sp),sp ;元のスタックポインタ ;割り込み許可 move.w (sp)+,sr ;カウンタを合成する mulu.w #50,d0 cmp.b d1,d0 bls @f add.w #$0100,d0 @@: move.b d1,d0 subq.w #1,d0 99: tst.l d0 movem.l (sp)+,d1-d7/a0-a6 rts dummy_routine: rts